package com.jvup.common.widget.adapter.auto;

import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;

import com.jvup.common.collect.ListUtil;
import com.jvup.common.widget.adapter.auto.annotation.AdapterEntityBind;

import java.util.List;

import androidx.annotation.LayoutRes;
import androidx.annotation.NonNull;
import androidx.databinding.DataBindingUtil;
import androidx.databinding.ViewDataBinding;

/**
 * 自动适配绑定Adapter,适用于基础的AdapterView
 * @param <T> 用于自动适配的 ViewModel 类型
 */
public class SummerBindAdapter<T extends AutoVariable> extends BaseAdapter {

	/** 用于缓存ViewHolder到RootView的Tag */
	private static final int HOLDER_TAG = 3 << 24;
	/** 无效ID */
	private static final int INVALID = -1;

	/** ViewModel数据列表 */
	private final List<T> dataList;

	/** 事件处理器 */
	private AutoVariable eventProcess;

	/** ViewModel类型，需要从中获取 {@link AdapterEntityBind} 注解读取LayoutRid*/
	private Class<?> clz;
	/** layoutRid 用于构建项目RootView */
	private int rootViewId = INVALID;

	/**
	 * 通过ViewModel提取layoutRid，如果dataList为空，则无法提取会并会导致后续异常
	 * @return layoutRid
	 */
	private int fetchRootViewId() {
		if(rootViewId == INVALID) {
			if(clz == null && dataList != null) {
				clz = dataList.isEmpty() ? null : dataList.get(0).getClass();
			}
			if(clz != null && clz.isAnnotationPresent(AdapterEntityBind.class)) {
				AdapterEntityBind adapterEntityBind = clz.getAnnotation(AdapterEntityBind.class);
				rootViewId = adapterEntityBind.viewRid();
			}
		}
		return rootViewId;
	}

	/**
	 * @param dataList 包含子项数据的ViewModel
	 */
	public SummerBindAdapter(@NonNull List<T> dataList) {
		this(dataList, null);
	}

	/**
	 * @param dataList 包含子项数据的ViewModel
	 * @param eventProcess 设置给子项绑定的事件处理器
	 */
	public SummerBindAdapter(@NonNull List<T> dataList, AutoVariable eventProcess) {
		this(dataList, eventProcess, INVALID);
		fetchRootViewId();
	}

	/**
	 * 在某些特殊情况下，期望没有数据是也能生成一部分布局，需要先制定布局ID，否则需要等待到DataList添加数据时才会构建布局
	 * @param dataList 包含子项数据的ViewModel
	 * @param rootViewId 可以提前指定子项布局的layoutID
	 */
	public SummerBindAdapter(@NonNull List<T> dataList, @LayoutRes int rootViewId) {
		this(dataList, null, rootViewId);
	}

	/**
	 * 在某些特殊情况下，期望没有数据是也能生成一部分布局，需要先制定布局ID，否则需要等待到DataList添加数据时才会构建布局
	 * @param dataList 包含子项数据的ViewModel
	 * @param eventProcess 设置给子项绑定的事件处理器
	 * @param rootViewId 可以提前指定子项布局的layoutID
	 */
	public SummerBindAdapter(@NonNull List<T> dataList, AutoVariable eventProcess, @LayoutRes int rootViewId) {
		this.dataList = dataList;
		this.eventProcess = eventProcess;
		this.rootViewId	= rootViewId;
	}

	/**
	 * 设置事件处理器到所有项目View并进行绑定
	 * @param eventProcess 事件处理器
	 */
	public void setEventProcess(AutoVariable eventProcess) {
		this.eventProcess = eventProcess;
		notifyDataSetChanged();
	}

	/**
	 * 获取所有数据列表
	 * @return viewModel 数据列表
	 */
	public List<T> getDataList() {
		return dataList;
	}

	/**
	 * 获取所有项目的数量，如果列表为NULL则返回0
	 * @return 子项目统计数
	 */
	@Override
	public int getCount() {
		return dataList == null ? 0 : dataList.size();
	}

	@Override
	public Object getItem(int position) {
		return dataList.get(position);
	}

	@Override
	public long getItemId(int position) {
		return position;
	}

	@Override
	public View getView(int position, View convertView, ViewGroup parent) {

		// 获取ViewHolder缓存
		ViewHolder viewHolder = convertView == null ? null : (ViewHolder) convertView.getTag(HOLDER_TAG);

		// 如果ViewHolder缓存不存在，进入ViewHolder构建流程
		if(viewHolder == null) {
			// 从当前View中获取viewDataBinder
			ViewDataBinding binding = DataBindingUtil.getBinding(convertView);
			// 如果 viewDataBinder 不存在则，则说明 convertView 未创建或则 convertView 并非通过 dataBind 创建，重建 convertView 通过dataBind
			if(binding == null) {
				LayoutInflater inflater = LayoutInflater.from(parent.getContext());
				binding = DataBindingUtil.inflate(inflater,fetchRootViewId(),parent,false);
				convertView = binding.getRoot();
			}
			// 构建ViewHolder
			viewHolder = new ViewHolder(binding);
			// 缓存ViewHolder，为了使重复使用时，能获得View，所以这里吧构造好的ViewHolder保存起来。
			convertView.setTag(HOLDER_TAG,viewHolder);
		}

		// 获得对应位置的数据
		T data = ListUtil.range(dataList, position) ? dataList.get(position) : null;

		// 绑定替换原 convertView 的内容 viewModel
		viewHolder.bindData(data);
		// 绑定替换原 convertView 的内容 eventProcess
		viewHolder.bindData(eventProcess);

		return convertView;
	}

	/**
	 * 缓存binder的处理器，负责绑定数据
	 */
	protected class ViewHolder {
		protected final ViewDataBinding viewDataBinding;

		public ViewHolder(ViewDataBinding viewDataBinding) {
			this.viewDataBinding = viewDataBinding;
		}

		public void bindData(AutoVariable observable) {
			if(observable != null) {
				observable.bindVariable(viewDataBinding);
			}
		}
	}

}
